/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.yonsei.iwb.sdt.refinement.generator;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;
import java.util.List;
import java.util.Vector;
import org.yonsei.iwb.sdt.algorithm.DCSSearcher;
import org.yonsei.iwb.sdt.datastructure.tree.BranchingType;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import org.yonsei.iwb.sdt.ontology.PropertyArc;
import org.yonsei.iwb.sdt.refinement.ConjunctionRefinement;
import org.yonsei.iwb.sdt.refinement.DLConstructors;
import org.yonsei.iwb.sdt.refinement.ExpandingHistory;
import org.yonsei.iwb.sdt.refinement.ExpandingHistorySet;
import org.yonsei.iwb.sdt.refinement.Refinement;
import org.yonsei.iwb.sdt.refinement.RefinementType;
import org.yonsei.iwb.sdt.util.SDTLog;
import org.yonsei.iwb.sdt.util.UtilFunctions;

/**
 *
 * @author JDK
 */
public class ConjunctionRefinementMaker extends Thread{

    private Model model;
    private Vector<Resource> instanceSet;
    private Resource cenclass;
    private Resource conclass;
    private PropertyArc pa;
    private Vector<PropertyArc> hisPAset;    
    private DecomposeCandidateSet dcs;
    private QuantificationRefinementMaker qrm;

    public ConjunctionRefinementMaker(Model model, Vector<Resource> instanceSet) {
        this.model = model;
        this.instanceSet = instanceSet;
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.CONJUNTION);
    }
    
    public ConjunctionRefinementMaker(Model model, Resource cenclass, Resource conclass, Vector<Resource> instanceSet, DecomposeCandidateSet dcs) {
        this.model = model;
        this.cenclass = cenclass;
        this.conclass = conclass;
        this.instanceSet = instanceSet;
        this.dcs =dcs;        
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.CONJUNTION);
    }
    
    public ConjunctionRefinementMaker(Model model, Resource cenclass, Resource conclass, PropertyArc pa, Vector<PropertyArc> hisPAset , Vector<Resource> instanceSet, DecomposeCandidateSet dcs) {
        this.model = model;
        this.cenclass = cenclass;
        this.conclass = conclass;
        this.pa = pa;
        this.hisPAset = hisPAset;                
        this.instanceSet = instanceSet;
        this.dcs =dcs;        
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.CONJUNTION);
    }
    
    @Override
    public synchronized void run() {
        long startTime = System.currentTimeMillis();          
        boolean gen = decomposeCandidateOfCR();
        DCSSearcher.FLAGNUM--;
        long endTime = System.currentTimeMillis();        
        if(gen){
            SDTLog.log(SDTLog.DETAIL,"# CR :  "+this.cenclass.getLocalName() +" AND : "+ this.conclass.getLocalName()+" is generated..."+((endTime - startTime)/1000.0f)+"s)\n");            
        }else{
            SDTLog.log(SDTLog.DETAIL,"# - CR :  "+this.cenclass.getLocalName() +" AND : "+ this.conclass.getLocalName()+" is NOT generated..."+((endTime - startTime)/1000.0f)+"s)\n");            
        }
        
    }

    private boolean decomposeCandidateOfCR() {
        if (hisPAset == null) {
            Vector<Refinement> refset = this.refinementGenerator(cenclass, conclass);
            if(refset!=null){
                this.dcs.add(new DecomposeCandidate(refset, RefinementType.CONJUNTION));
                return true;
            }else{
                return false;
            }
        } else {
            DecomposeCandidateSet newdcs = this.refinementGenerator(pa, cenclass, conclass, hisPAset);
            if(newdcs != null){
                this.dcs.addAll(newdcs);
                return true;
            }else{
                return false;
            }
        }
        
    }
    
    public Vector<Refinement> refinementGenerator(Resource centerclass, Resource conclass){
        
        Vector<Refinement> rset = new Vector<Refinement>();        
        Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);


        Refinement pref = new ConjunctionRefinement("", centerclass, conclass);
        Refinement nref = new ConjunctionRefinement(DLConstructors.NEGATION, centerclass, conclass);
        nref.setBranchingType(BranchingType.NEGATION_TYPE);
        
        Vector<Resource> css = this.getSatisfiedInstanceSet(centerclass, conclass);
        for (int i = 0; i < css.size(); i++) {
            Resource result = css.get(i);
            if (instanceSet.contains(result)) {
                pref.setInstanceSet(result);
                cloneSet.remove(result);
            }            
        }
        
        if(!cloneSet.isEmpty()&& !pref.getInstanceSet().isEmpty()){
            nref.setInstanceSet(cloneSet);
            rset.add(pref);
            rset.add(nref);
        }else{
            return null;
        }
        
        return rset;        
    }
    
    /**
     * 
     * @param pa
     * @param centerclass
     * @param conclass
     * @param paSet
     * @return 
     */
    public DecomposeCandidateSet refinementGenerator(PropertyArc pa, Resource centerclass, Resource conclass, Vector<PropertyArc> paSet) {
                
        Vector<PropertyArc> propertyHistory = new Vector(paSet);
        propertyHistory.add(pa);

        List<Resource> css = this.getSatisfiedInstanceSet(centerclass, conclass);

        ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css);
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();

        for (int i = 0; i < ehs.size(); i++) {
            ExpandingHistory eh = ehs.get(i);
            Vector<Refinement> refset = new Vector<Refinement>();
            Refinement pref = new ConjunctionRefinement("", eh, centerclass, conclass);
            Refinement nref = new ConjunctionRefinement(DLConstructors.NEGATION, eh, centerclass, conclass);
            nref.setBranchingType(BranchingType.NEGATION_TYPE);

            Vector<Resource> is = eh.getInstanceSet();

//            UtilFunctions.printVectorOfResource(is);

            Vector<Resource> cloneSet = new Vector(this.instanceSet);

            for (int j = 0; j < is.size(); j++) {
                Resource result = is.get(j);
                if (this.instanceSet.contains(result)) {
                    pref.setInstanceSet(result);
                    cloneSet.remove(result);
                }
            }
//            UtilFunctions.printVectorOfResource(cloneSet);
            if (!cloneSet.isEmpty() && !pref.getInstanceSet().isEmpty()) {
                nref.setInstanceSet(cloneSet);
                refset.add(pref);
                refset.add(nref);
            } else {
                continue;
            }

            DecomposeCandidate dc = new DecomposeCandidate(refset, pa, RefinementType.CONJUNTION);
//            dc.printDecomposeCandidateDetail();
            dcs.add(dc);
        }
        
        return dcs;
    }

    private Vector<Resource> getSatisfiedInstanceSet(Resource centerclass, Resource conclass) {
        Vector<Resource> css = new Vector<Resource>();
        
        ResIterator cenres = this.model.listResourcesWithProperty(RDF.type, centerclass);
        ResIterator conres = this.model.listResourcesWithProperty(RDF.type, conclass);
        
        List<Resource> cen = cenres.toList();
        List<Resource> con = conres.toList();
        
        if(cen.size() < con.size()){
            for (int i = 0; i < cen.size(); i++) {            
                if(con.contains(cen.get(i))){
                    if(!css.contains(cen.get(i))){
                        css.add(cen.get(i));                    
                    }                
                }
            }
        }else{
            for (int i = 0; i < con.size(); i++) {            
                if(cen.contains(con.get(i))){
                    if(!css.contains(con.get(i))){
                        css.add(con.get(i));                    
                    }                
                }
            }            
        }

        return css;
    }

    private Vector<Property> copyPropertySet(Vector<Property> propertySet) {
        Vector<Property> copy = new Vector<Property>();
        for (int i = 0; i < propertySet.size(); i++) {
            copy.add(propertySet.get(i));
        }
        return copy;
    }
}
